package com.linwoain.wififileserver

import android.Manifest
import android.content.Context
import android.net.wifi.WifiManager
import android.os.Bundle
import android.os.Environment
import android.support.v7.app.AppCompatActivity
import com.koushikdutta.async.http.body.MultipartFormDataBody
import com.koushikdutta.async.http.server.AsyncHttpServer
import kotlinx.android.synthetic.main.activity_main.*
import org.jetbrains.anko.AnkoLogger
import org.jetbrains.anko.info
import org.jetbrains.anko.toast
import org.jetbrains.anko.warn
import permissions.dispatcher.NeedsPermission
import permissions.dispatcher.OnNeverAskAgain
import permissions.dispatcher.OnPermissionDenied
import permissions.dispatcher.RuntimePermissions
import java.io.File
import java.io.FileOutputStream

@RuntimePermissions(kotlin = true)
class MainActivity : AppCompatActivity(), AnkoLogger {


    override val loggerTag: String
        get() = "anko_log"

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        startServerWithCheck()
    }


    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>,
                                            grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        onRequestPermissionsResult(requestCode, grantResults)
    }

    @OnPermissionDenied(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    internal fun onStorageDenied() {
        toast("权限请求被拒绝")
    }

    @OnNeverAskAgain(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    internal fun onStorageNeverAskAgain() {
        toast("请在设置中打开读写外置存储权限")
    }

    val server = AsyncHttpServer()

    @NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    internal fun startServer() {
        val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager

        val wifiInfo = wifiManager.connectionInfo
        val ipAddress = wifiInfo.ipAddress
        val ip = intToIp(ipAddress)

        server.get("/(js|css)/.*") {//静态资源路由
            request, response ->
            val path = request.path
            info("下载静态资源：" + path)
            val stream = assets.open(path.removePrefix("/"))
            response.sendStream(stream, stream.available().toLong())
        }
        server.post("/upload") {//处理上传逻辑
            request, response ->

            info("接收到上传请求")

            val body = request.body as MultipartFormDataBody
            var file: File? = null

            body.setMultipartCallback {

                if (it.isFile) {
                    val path = Environment.getExternalStorageDirectory().absolutePath + File.separator + it.filename
                    info("临时上传地址：$path")
                    file = File(path)
                    val outStream = FileOutputStream(file)
                    body.setDataCallback { _, bb ->
                        info("上传中。。。")
                        outStream.write(bb.allByteArray)
                        outStream.flush()
                        bb.recycle()
                    }
                    body.setEndCallback {
                        if (it != null) {
                            info("内部逻辑出错")
                            it.printStackTrace()
                            response.code(500).end()
                        } else {
                            info("运行结束，返回200")
                            response.code(200).end()
                        }
                        outStream.close()

                    }
                } else {
                    val pathname = it.name + File.separator + file?.name
                    info("期望地址：$pathname")
                    if (file?.absolutePath != pathname) {
                        info("期望地址与临时地址不同，移动到期望地址")
                        val dst = File(pathname)
                        if (dst.exists()) {
                            info("文件已存在")
                            if (file?.md5() == dst.md5()) {
                                warn("目标文件与临时文件md5值相同，删除临时文件")
                                file?.delete()
                            } else {
                                warn("目标文件与临时文件md5值不同，决定删除旧文件")
                                if (dst.delete()) {
                                    info("删除旧文件成功，复制临时文件到目标路径")
                                    file?.renameTo(dst)
                                } else {
                                    val newPath = dst.nameWithoutExtension + System.currentTimeMillis().toString() + dst.extension
                                    info("删除旧文件失败，保存临时文件到目标路径并命名为$newPath")
                                    file?.renameTo(File(newPath))

                                }

                            }
                        } else {
                            file?.renameTo(dst)
                        }
                    }
                }

            }

        }

        server.get("/") { request, response ->
            //处理浏览逻辑
            run {
                val path = request.query.getString("path")
                info("接收到的参数为：path=$path")
                val builder = StringBuilder()
                val s: String = if (path.isNullOrEmpty() or (path == "/")) {
                    Environment.getExternalStorageDirectory().absolutePath
                } else {
                    path
                }

                val file = File(s)
                if (!file.isDirectory) {
                    info("返回文件：" + file.absolutePath)
                    response.sendFile(file)
                } else {
                    if (s != Environment.getExternalStorageDirectory().absolutePath) {
                        builder.append(
                                """<div><a href="/?path=${path.substringBeforeLast(
                                        "/")}">返回上级菜单</a></div>""")
                    }

                    file.listFiles().forEach {
                        builder.append("""
                               <p><a href="/?path=${it.absolutePath}">${it.name}</a>
                               <a  href="javascript:del('${it.absolutePath}',${it.isFile})">  x  </a>
                               </p>

                            """)
                    }

                    val string = String(assets.open("file.html").readBytes())
                    val responseHtml = string.replace("#content", builder.toString()).replace("#path@", s)

                    response.send(responseHtml)
                }
            }
        }
        server.listen(5000)
        info("服务开始 ==> http://$ip:5000")

        tv_ip.text = ip + ":5000"

    }

    override fun onDestroy() {
        super.onDestroy()
        stopServer()
    }

    private fun stopServer() {
        server.stop()
    }

    private fun intToIp(i: Int): String {

        return (i and 0xFF).toString() + "." +
                (i shr 8 and 0xFF) + "." +
                (i shr 16 and 0xFF) + "." +
                (i shr 24 and 0xFF)
    }

}
